/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_RENDERQUEUE_H
#define M_RENDERQUEUE_H

#include "renderable.h"
#include "camera.h"
#include "types.h"
#include "mutex.h"

#include <string>
#include <vector>
#include <map>

namespace Engine
{
	/**
	*   Class to manage the scene object rendering queue.
	*/
	class RenderQueue
	{
	public:

		/************************************* TYPES **********************************************************/

		typedef std::vector<RenderablePtr> RenderableVector;

		class RenderableSortGroup
		{
		public:
			RenderableSortGroup(REAL dist, const std::string& mat, const RenderableVector* rends)
				:MinRenderDistance(dist)
				,MaterialName(mat)
				,Renderables(rends)
			{}
			bool operator < (const RenderableSortGroup& rhs)const
			{
				return MinRenderDistance > rhs.MinRenderDistance;
			}

			REAL MinRenderDistance;
			std::string MaterialName;
			const RenderableVector* Renderables;
		};

		typedef std::map<std::string, RenderableVector> RenderableGroupMap;
		typedef std::multimap<std::string, RenderableVector> RenderableGroupMultiMap;

		typedef std::vector<RenderableSortGroup> RenderableSortGroupVector;

		/******************************************************************************************************/

		RenderQueue();

		virtual ~RenderQueue();

		/**
		*   Add a renderable object to the queue.
		*   @param  pRend Pointer to the Renderable to be added to the queue
        */
		void AddRenderable(RenderablePtr rend);

		/**
		*   Clear current queue from renderable objects.
		*/
		void Reset();

		/**
		*   Sort object by distance to camera and materials, exclude tranparents.
		*/
		void Sort(const Camera* camera);

		/**
		*    Return opaque objects sorted by distance to camera.
		*/
		const RenderableSortGroupVector& GetSolids() const;

		/**
		*    Return transparent objects sorted by distance to camera.
		*/
		const RenderableSortGroupVector& GetTransparents() const;

	private:

		void SortTransparents(RenderableGroupMultiMap& group, RenderableSortGroupVector& sortGroup, const Camera* camera);
		void SortGroup(RenderableGroupMap& group, RenderableSortGroupVector& sortGroup, const Camera* camera, bool less = true);

	private:

		RenderableGroupMap      m_solids;
		RenderableGroupMultiMap m_transparents;

		RenderableSortGroupVector m_sortSolids;
		RenderableSortGroupVector m_sortTransparents;

		Mutex m_addMutex;
	};
}

#endif
